#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
账单分析系统 - 最终版本
支持支付宝CSV和微信Excel格式的流水记录分析
提供4级分类、智能归类、数据导出等功能
"""

import pandas as pd
import os
import re
import json
from datetime import datetime, timedelta
from typing import Dict, List, Tuple, Optional
from tabulate import tabulate
import warnings
warnings.filterwarnings('ignore')


class BillAnalyzerFinal:
    """
    账单分析器 - 最终版本
    
    功能包括：
    1. 支持支付宝CSV和微信Excel格式
    2. 4级智能分类系统
    3. 高频特征提取和智能归类
    4. 数据导出（Excel格式）
    5. 用户昵称管理
    6. 月度汇总统计
    7. 交易失败分析
    """
    
    def __init__(self, bill_folder: str = "zhangdan"):
        """
        初始化账单分析器
        
        Args:
            bill_folder: 账单文件夹路径，默认为"zhangdan"
        """
        self.bill_folder = bill_folder
        self.user_nicknames = {}  # 存储用户昵称
        self.bills_data = []  # 存储处理后的账单数据
        self.field_mapping = self._init_field_mapping()
        
        # 新增：数据预处理队列
        self.failed_transactions = []  # 交易失败队列
        self.cross_platform_transfers = []  # 疑似跨平台互转队列
        self.same_platform_transfers = []  # 疑似同平台互转队列
        self.other_queue = []  # 其他队列
        self.need_level2_keywords = []  # 需要补充二级关键词队列
        self.need_level3_keywords = []  # 需要补充三级关键词队列
        self.need_level4_keywords = []  # 需要补充四级关键词队列
        self.valid_bills_data = []  # 有效账单数据（用于四级分类）
        self.suggested_keywords = []  # 建议增加关键词记录
        
    def _init_field_mapping(self) -> Dict[str, Dict[str, str]]:
        """
        初始化字段映射关系
        
        Returns:
            Dict: 字段映射字典
        """
        return {
            'alipay': {
                '交易时间': 'datetime',
                '交易对方': 'counterparty', 
                '商品说明': 'description',
                '收/支': 'type',
                '金额': 'amount',
                '收/付款方式': 'payment_method',
                '交易状态': 'status',
                '交易分类': 'category',
                '对方账号': 'counterparty_account',
                '备注': 'remark'
            },
            'wechat': {
                '交易时间': 'datetime',
                '交易类型': 'type',
                '交易对方': 'counterparty',
                '商品': 'description', 
                '收/支': 'income_expense',
                '金额(元)': 'amount',
                '支付方式': 'payment_method',
                '当前状态': 'status',
                '交易单号': 'transaction_id',
                '商户单号': 'merchant_id',
                '备注': 'remark'
            }
        }
    
    def load_bills(self) -> None:
        """
        加载账单文件
        
        自动识别并处理zhangdan文件夹中的支付宝CSV和微信Excel文件
        """
        if not os.path.exists(self.bill_folder):
            print(f"错误：账单文件夹 '{self.bill_folder}' 不存在")
            return
            
        files = os.listdir(self.bill_folder)
        alipay_files = [f for f in files if f.endswith('.csv')]
        wechat_files = [f for f in files if f.endswith('.xlsx')]
        
        print(f"发现 {len(alipay_files)} 个支付宝文件，{len(wechat_files)} 个微信文件")
        
        # 处理支付宝文件
        for file in alipay_files:
            self._process_alipay_file(file)
            
        # 处理微信文件
        for file in wechat_files:
            self._process_wechat_file(file)
    
    def _process_alipay_file(self, filename: str) -> None:
        """
        处理支付宝CSV文件
        
        Args:
            filename: 文件名
        """
        filepath = os.path.join(self.bill_folder, filename)
        print(f"正在处理支付宝文件: {filename}")
        
        try:
            # 先读取文件内容找到数据开始行
            with open(filepath, 'r', encoding='gbk', errors='ignore') as f:
                lines = f.readlines()
            
            # 查找包含"交易时间"的行
            data_start_row = None
            for i, line in enumerate(lines):
                if '交易时间' in line and '交易分类' in line:
                    data_start_row = i
                    break
            
            if data_start_row is None:
                print(f"无法找到数据开始行，跳过文件 {filename}")
                return
            
            print(f"数据从第 {data_start_row + 1} 行开始")
            
            # 提取用户信息和时间范围
            self._extract_file_info(filepath, 'alipay')
            
            # 使用pandas读取数据，跳过前面的行
            df = pd.read_csv(filepath, encoding='gbk', skiprows=data_start_row)
            
            # 处理数据
            processed_data = self._process_alipay_data(df)
            self.bills_data.extend(processed_data)
            
        except Exception as e:
            print(f"处理支付宝文件 {filename} 时出错: {e}")
    
    def _process_wechat_file(self, filename: str) -> None:
        """
        处理微信Excel文件
        
        Args:
            filename: 文件名
        """
        filepath = os.path.join(self.bill_folder, filename)
        print(f"正在处理微信文件: {filename}")
        
        try:
            # 直接读取微信文件，跳过前15行（表头在第16行，索引为15）
            df = pd.read_excel(filepath, skiprows=15, header=0)
            print(f"微信数据列名: {list(df.columns)}")
            
            # 清理列名，移除多余的空格和特殊字符
            df.columns = [str(col).strip() for col in df.columns]
            print(f"清理后的微信数据列名: {list(df.columns)}")
            
            # 检查是否有数据行
            if len(df) == 0:
                print("微信文件没有数据行")
                return
            
            # 检查第一行是否是表头
            first_row = df.iloc[0]
            if '交易时间' in str(first_row.iloc[0]):
                print("第一行是表头，重新设置列名")
                # 使用第一行作为列名
                df.columns = df.iloc[0]
                df = df.drop(df.index[0]).reset_index(drop=True)
                print(f"重新设置后的列名: {list(df.columns)}")
                
                # 清理列名，移除多余的空格和特殊字符
                df.columns = [str(col).strip() for col in df.columns]
                print(f"清理后的列名: {list(df.columns)}")
            
            # 提取用户信息和时间范围
            self._extract_file_info(filepath, 'wechat')
            
            # 处理数据
            processed_data = self._process_wechat_data(df)
            self.bills_data.extend(processed_data)
            
        except Exception as e:
            print(f"处理微信文件 {filename} 时出错: {e}")
            import traceback
            traceback.print_exc()
    
    def _find_data_start_row(self, df: pd.DataFrame) -> Optional[int]:
        """
        查找数据开始行
        
        Args:
            df: DataFrame对象
            
        Returns:
            Optional[int]: 数据开始行号，如果未找到返回None
        """
        for i, row in df.iterrows():
            # 查找包含"交易时间"或"时间"的行
            row_str = ' '.join([str(cell) for cell in row.values if pd.notna(cell)])
            if '交易时间' in row_str or '时间' in row_str:
                return i
        return None
    
    def _extract_file_info(self, filepath: str, platform: str) -> None:
        """
        提取文件信息（用户昵称、时间范围等）
        
        Args:
            filepath: 文件路径
            platform: 平台类型（alipay/wechat）
        """
        try:
            with open(filepath, 'r', encoding='gbk', errors='ignore') as f:
                content = f.read()
                
            # 提取时间范围
            time_pattern = r'(\d{4}-\d{2}-\d{2})'
            times = re.findall(time_pattern, content)
            if len(times) >= 2:
                start_time = times[0]
                end_time = times[1]
                print(f"时间范围: {start_time} 到 {end_time}")
            
            # 提取用户信息
            user_key = f"{platform}_user"
            if user_key not in self.user_nicknames:
                # 尝试从文件中提取用户名
                name_match = re.search(r'姓名：(.+)', content)
                if name_match:
                    self.user_nicknames[user_key] = name_match.group(1).strip()
                else:
                    self.user_nicknames[user_key] = f"用户_{len(self.user_nicknames) + 1}"
                
        except Exception as e:
            print(f"提取文件信息时出错: {e}")
    
    def _process_alipay_data(self, df: pd.DataFrame) -> List[Dict]:
        """
        处理支付宝数据
        
        Args:
            df: DataFrame对象
            
        Returns:
            List[Dict]: 处理后的账单数据列表
        """
        processed_data = []
        
        for _, row in df.iterrows():
            if pd.isna(row.get('交易时间')):
                continue
                
            try:
                # 解析时间
                datetime_str = str(row['交易时间'])
                if ' ' in datetime_str:
                    dt = datetime.strptime(datetime_str, '%Y-%m-%d %H:%M:%S')
                else:
                    dt = datetime.strptime(datetime_str, '%Y-%m-%d')
                
                # 处理金额，确保格式为整数+2位小数
                amount_str = str(row.get('金额', '0')).replace(',', '').replace('¥', '').replace('￥', '')
                try:
                    amount = round(float(amount_str), 2) if amount_str.replace('.', '').isdigit() else 0.00
                except:
                    amount = 0.00
                
                # 确定收支类型（支付宝中"不计收支"表示不计收支）
                income_expense = str(row.get('收/支', ''))
                if '不计收支' in income_expense:
                    bill_type = 'neutral'  # 不计收支
                elif '收入' in income_expense or '收款' in income_expense:
                    bill_type = 'income'
                elif '支出' in income_expense or '付款' in income_expense:
                    bill_type = 'expense'
                else:
                    bill_type = 'unknown'
                
                bill_data = {
                    'platform': 'alipay',
                    'datetime': dt,
                    'counterparty': str(row.get('交易对方', '')),
                    'description': str(row.get('商品说明', '')),
                    'type': bill_type,
                    'amount': amount,
                    'payment_method': str(row.get('收/付款方式', '')),
                    'status': str(row.get('交易状态', '')),
                    'original_category': str(row.get('交易分类', '')),  # 保留原始交易分类
                    'remark': str(row.get('备注', '')),
                    'raw_data': row.to_dict()
                }
                
                processed_data.append(bill_data)
                
            except Exception as e:
                print(f"处理支付宝数据行时出错: {e}")
                continue
                
        return processed_data
    
    def _process_wechat_data(self, df: pd.DataFrame) -> List[Dict]:
        """
        处理微信数据
        
        Args:
            df: DataFrame对象
            
        Returns:
            List[Dict]: 处理后的账单数据列表
        """
        processed_data = []
        
        # 打印列名以便调试
        print(f"微信数据列名: {list(df.columns)}")
        
        for _, row in df.iterrows():
            # 检查是否有有效的时间数据
            time_col = None
            for col in df.columns:
                if '时间' in str(col) or 'time' in str(col).lower():
                    time_col = col
                    break
            
            if time_col is None or pd.isna(row.get(time_col)):
                continue
                
            try:
                # 解析时间
                datetime_str = str(row[time_col])
                if ' ' in datetime_str:
                    dt = datetime.strptime(datetime_str, '%Y-%m-%d %H:%M:%S')
                else:
                    dt = datetime.strptime(datetime_str, '%Y-%m-%d')
                
                # 查找金额列
                amount_col = None
                for col in df.columns:
                    if '金额' in str(col) or 'amount' in str(col).lower():
                        amount_col = col
                        break
                
                # 处理金额，确保格式为整数+2位小数
                amount = 0.00
                if amount_col and not pd.isna(row.get(amount_col)):
                    amount_str = str(row[amount_col]).replace(',', '').replace('¥', '').replace('￥', '')
                    try:
                        amount = round(float(amount_str), 2) if amount_str.replace('.', '').replace('-', '').isdigit() else 0.00
                    except ValueError:
                        amount = 0.00
                
                # 查找收支类型列
                type_col = None
                for col in df.columns:
                    if '收' in str(col) and '支' in str(col):
                        type_col = col
                        break
                
                # 确定收支类型
                bill_type = 'unknown'
                if type_col and not pd.isna(row.get(type_col)):
                    income_expense = str(row[type_col])
                    if income_expense == '/':
                        bill_type = 'neutral'  # 不计收支
                    elif '收入' in income_expense or '收款' in income_expense:
                        bill_type = 'income'
                    elif '支出' in income_expense or '付款' in income_expense:
                        bill_type = 'expense'
                
                # 查找其他字段
                counterparty = ''
                description = ''
                payment_method = ''
                status = ''
                original_category = ''
                remark = ''
                
                for col in df.columns:
                    col_str = str(col).lower()
                    if '对方' in col_str or 'counterparty' in col_str:
                        counterparty = str(row[col]) if not pd.isna(row[col]) else ''
                    elif '商品' in col_str or 'description' in col_str:
                        description = str(row[col]) if not pd.isna(row[col]) else ''
                    elif '支付' in col_str and '方式' in col_str:
                        payment_method = str(row[col]) if not pd.isna(row[col]) else ''
                    elif '状态' in col_str or 'status' in col_str:
                        status = str(row[col]) if not pd.isna(row[col]) else ''
                    elif '类型' in col_str or 'category' in col_str:
                        original_category = str(row[col]) if not pd.isna(row[col]) else ''
                    elif '备注' in col_str or 'remark' in col_str:
                        remark = str(row[col]) if not pd.isna(row[col]) else ''
                
                bill_data = {
                    'platform': 'wechat',
                    'datetime': dt,
                    'counterparty': counterparty,
                    'description': description,
                    'type': bill_type,
                    'amount': amount,
                    'payment_method': payment_method,
                    'status': status,
                    'original_category': original_category,
                    'remark': remark,
                    'raw_data': row.to_dict()
                }
                
                processed_data.append(bill_data)
                
            except Exception as e:
                print(f"处理微信数据行时出错: {e}")
                continue
                
        print(f"微信数据处理完成，共处理 {len(processed_data)} 条记录")
        return processed_data
    
    def preprocess_bills(self) -> None:
        """
        数据预处理：分离失败交易、互转记录等
        """
        print("开始数据预处理...")
        
        # 1. 分离交易失败记录
        self._filter_failed_transactions()
        
        # 2. 检测跨平台互转
        self._detect_cross_platform_transfers()
        
        # 3. 检测同平台互转
        self._detect_same_platform_transfers()
        
        # 4. 生成有效账单数据
        self._generate_valid_bills()
        
        print(f"数据预处理完成：")
        print(f"  原始数据: {len(self.bills_data)} 条")
        print(f"  失败交易: {len(self.failed_transactions)} 条")
        print(f"  跨平台互转: {len(self.cross_platform_transfers)} 条")
        print(f"  同平台互转: {len(self.same_platform_transfers)} 条")
        print(f"  有效数据: {len(self.valid_bills_data)} 条")
    
    def _filter_failed_transactions(self) -> None:
        """
        过滤交易失败记录
        """
        failed_keywords = ['失败', '退款', '取消', '异常', '错误', '关闭', '超时']
        
        remaining_bills = []
        for bill in self.bills_data:
            status = str(bill.get('status', '')).lower()
            if any(keyword in status for keyword in failed_keywords):
                bill['filter_reason'] = '交易失败'
                self.failed_transactions.append(bill)
            else:
                remaining_bills.append(bill)
        
        self.bills_data = remaining_bills
    
    def _detect_cross_platform_transfers(self) -> None:
        """
        检测跨平台互转记录
        """
        # 按时间排序
        sorted_bills = sorted(self.bills_data, key=lambda x: x['datetime'])
        
        remaining_bills = []
        i = 0
        while i < len(sorted_bills):
            current_bill = sorted_bills[i]
            matched = False
            
            # 检查后续5分钟内的记录
            j = i + 1
            while j < len(sorted_bills):
                next_bill = sorted_bills[j]
                time_diff = (next_bill['datetime'] - current_bill['datetime']).total_seconds()
                
                # 超过5分钟，停止检查
                if time_diff > 300:  # 5分钟 = 300秒
                    break
                
                # 检查是否为跨平台且金额相同
                if (current_bill['platform'] != next_bill['platform'] and 
                    abs(current_bill['amount'] - next_bill['amount']) < 0.01):
                    
                    # 记录跨平台互转
                    transfer_record = {
                        'bill1': current_bill,
                        'bill2': next_bill,
                        'time_diff': time_diff,
                        'amount': current_bill['amount']
                    }
                    self.cross_platform_transfers.append(transfer_record)
                    
                    # 标记为已匹配
                    current_bill['filter_reason'] = '跨平台互转'
                    next_bill['filter_reason'] = '跨平台互转'
                    matched = True
                    break
                
                j += 1
            
            if not matched:
                remaining_bills.append(current_bill)
            
            i += 1
        
        self.bills_data = remaining_bills
    
    def _detect_same_platform_transfers(self) -> None:
        """
        检测同平台互转记录
        """
        # 按平台分组
        platform_groups = {}
        for bill in self.bills_data:
            platform = bill['platform']
            if platform not in platform_groups:
                platform_groups[platform] = []
            platform_groups[platform].append(bill)
        
        remaining_bills = []
        
        for platform, bills in platform_groups.items():
            # 按时间排序
            sorted_bills = sorted(bills, key=lambda x: x['datetime'])
            
            i = 0
            while i < len(sorted_bills):
                current_bill = sorted_bills[i]
                matched = False
                
                # 检查后续5分钟内的记录
                j = i + 1
                while j < len(sorted_bills):
                    next_bill = sorted_bills[j]
                    time_diff = (next_bill['datetime'] - current_bill['datetime']).total_seconds()
                    
                    # 超过5分钟，停止检查
                    if time_diff > 300:
                        break
                    
                    # 检查是否为同平台、不同交易对象且金额相同
                    if (current_bill['platform'] == next_bill['platform'] and 
                        current_bill['counterparty'] != next_bill['counterparty'] and
                        abs(current_bill['amount'] - next_bill['amount']) < 0.01):
                        
                        # 记录同平台互转
                        transfer_record = {
                            'bill1': current_bill,
                            'bill2': next_bill,
                            'time_diff': time_diff,
                            'amount': current_bill['amount'],
                            'platform': platform
                        }
                        self.same_platform_transfers.append(transfer_record)
                        
                        # 标记为已匹配
                        current_bill['filter_reason'] = '同平台互转'
                        next_bill['filter_reason'] = '同平台互转'
                        matched = True
                        break
                    
                    j += 1
                
                if not matched:
                    remaining_bills.append(current_bill)
                
                i += 1
        
        self.bills_data = remaining_bills
    
    def _generate_valid_bills(self) -> None:
        """
        生成有效账单数据（用于四级分类）
        """
        self.valid_bills_data = []
        for bill in self.bills_data:
            # 确保所有账单都有分类字段
            if 'category_level1' not in bill:
                bill['category_level1'] = '未分类'
            if 'category_level2' not in bill:
                bill['category_level2'] = '未分类'
            if 'category_level3' not in bill:
                bill['category_level3'] = '未分类'
            if 'category_level4' not in bill:
                bill['category_level4'] = '未分类'
            self.valid_bills_data.append(bill)

    def _custom_classify_level4(self) -> None:
        """
        基于user_nicknames.json的自定义四级分类
        """
        # 加载用户自定义分类规则
        self._load_custom_classification_rules()
        
        for bill in self.valid_bills_data:
            # 提取时间（小时）、交易对象、金额
            hour = bill['datetime'].hour
            counterparty = bill['counterparty']
            amount = bill['amount']
            description = bill.get('description', '')
            
            # 尝试匹配自定义规则
            matched_rule = self._match_custom_rule(hour, counterparty, amount, description)
            
            if matched_rule:
                # 检查商品说明关键词匹配
                if self._match_description_keywords(description, matched_rule.get('description_keywords', [])):
                    # 匹配成功，应用自定义分类
                    bill['custom_category_level4'] = matched_rule['category_level4']
                    bill['custom_classification_source'] = 'user_nicknames'
                else:
                    # 商品说明匹配失败，记录建议
                    self._record_suggested_keyword(bill, matched_rule, description)
            else:
                # 没有匹配到规则，继续使用通用分类
                pass
    
    def _load_custom_classification_rules(self) -> None:
        """
        加载用户自定义分类规则
        """
        try:
            with open('user_nicknames.json', 'r', encoding='utf-8') as f:
                data = json.load(f)
                self.custom_rules = data.get('custom_classification_rules', [])
        except FileNotFoundError:
            print("user_nicknames.json文件不存在，将创建默认文件")
            self.custom_rules = []
            self._create_default_user_nicknames()
        except Exception as e:
            print(f"加载user_nicknames.json失败: {e}")
            self.custom_rules = []
    
    def _create_default_user_nicknames(self) -> None:
        """
        创建默认的user_nicknames.json文件
        """
        default_data = {
            "description": "用户自定义分类规则配置文件",
            "usage": "在此文件中配置自定义四级分类规则",
            "custom_classification_rules": [
                {
                    "time_range": "16-20",
                    "counterparty": "刘峰强",
                    "amount_range": "30",
                    "description_keywords": ["转账", "微信", "收入"],
                    "category_level4": "夜班兼职"
                },
                {
                    "time_range": "08-18",
                    "counterparty": "江振文",
                    "amount_range": "30-90",
                    "description_keywords": ["转账", "微信", "收入"],
                    "category_level4": "日班兼职"
                }
            ]
        }
        
        with open('user_nicknames.json', 'w', encoding='utf-8') as f:
            json.dump(default_data, f, ensure_ascii=False, indent=2)
        
        self.custom_rules = default_data['custom_classification_rules']
        print("已创建默认user_nicknames.json文件")
    
    def _match_custom_rule(self, hour: int, counterparty: str, amount: float, description: str) -> Optional[Dict]:
        """
        匹配自定义规则
        
        Args:
            hour: 交易小时（0-23）
            counterparty: 交易对象
            amount: 交易金额
            description: 商品描述
            
        Returns:
            Dict: 匹配的规则，如果没有匹配返回None
        """
        for rule in self.custom_rules:
            # 检查时间范围
            if not self._match_time_range(hour, rule.get('time_range', '')):
                continue
            
            # 检查交易对象（精确匹配）
            if rule.get('counterparty', '') != counterparty:
                continue
            
            # 检查金额范围
            if not self._match_amount_range(amount, rule.get('amount_range', '')):
                continue
            
            # 所有条件都匹配
            return rule
        
        return None
    
    def _match_time_range(self, hour: int, time_range: str) -> bool:
        """
        匹配时间范围
        
        Args:
            hour: 当前小时（0-23）
            time_range: 时间范围字符串，如"16-20"
            
        Returns:
            bool: 是否匹配
        """
        if not time_range:
            return True
        
        try:
            if '-' in time_range:
                start_hour, end_hour = map(int, time_range.split('-'))
                return start_hour <= hour <= end_hour
            else:
                return hour == int(time_range)
        except:
            return False
    
    def _match_amount_range(self, amount: float, amount_range: str) -> bool:
        """
        匹配金额范围
        
        Args:
            amount: 当前金额
            amount_range: 金额范围字符串，如"30"、"30-90"、"0-0.5"
            
        Returns:
            bool: 是否匹配
        """
        if not amount_range:
            return True
        
        try:
            if '-' in amount_range:
                min_amount, max_amount = map(float, amount_range.split('-'))
                return min_amount <= amount <= max_amount
            else:
                return abs(amount - float(amount_range)) < 0.01
        except:
            return False
    
    def _match_description_keywords(self, description: str, keywords: List[str]) -> bool:
        """
        匹配商品描述关键词
        
        Args:
            description: 商品描述
            keywords: 关键词列表
            
        Returns:
            bool: 是否匹配
        """
        if not keywords:
            return True
        
        description_lower = description.lower()
        return any(keyword.lower() in description_lower for keyword in keywords)
    
    def _record_suggested_keyword(self, bill: Dict, rule: Dict, description: str) -> None:
        """
        记录建议增加的关键词
        
        Args:
            bill: 账单数据
            rule: 匹配的规则
            description: 商品描述
        """
        suggestion = {
            'datetime': bill['datetime'].strftime('%Y-%m-%d %H:%M:%S'),
            'counterparty': bill['counterparty'],
            'amount': bill['amount'],
            'description': description,
            'matched_rule': rule,
            'suggested_keywords': self._extract_potential_keywords(description)
        }
        self.suggested_keywords.append(suggestion)
    
    def _extract_potential_keywords(self, description: str) -> List[str]:
        """
        从商品描述中提取潜在关键词
        
        Args:
            description: 商品描述
            
        Returns:
            List[str]: 潜在关键词列表
        """
        # 简单的关键词提取逻辑
        keywords = []
        common_words = ['转账', '微信', '收入', '支出', '支付', '收款', '付款', '充值', '提现']
        
        for word in common_words:
            if word in description:
                keywords.append(word)
        
        return keywords

    def classify_bills(self) -> None:
        """
        对有效账单进行4级分类
        
        按照营业收入和营业总支出的4级分类体系进行分类
        """
        print("开始通用四级分类...")
        
        # 先进行自定义四级分类
        self._custom_classify_level4()
        
        # 然后进行通用四级分类
        for bill in self.valid_bills_data:
            try:
                # 第一级分类
                bill['category_level1'] = self._classify_level1(bill)
                
                # 如果是"其他"类型，移到其他队列
                if bill['category_level1'] == '其他':
                    bill['filter_reason'] = '其他类型'
                    self.other_queue.append(bill)
                    continue
                
                # 第二级分类
                bill['category_level2'] = self._classify_level2(bill)
                if bill['category_level2'] == '未分类':
                    bill['filter_reason'] = '需要补充二级关键词'
                    self.need_level2_keywords.append(bill)
                    continue
                
                # 第三级分类
                bill['category_level3'] = self._classify_level3(bill)
                if bill['category_level3'] == '未分类':
                    bill['filter_reason'] = '需要补充三级关键词'
                    self.need_level3_keywords.append(bill)
                    continue
                
                # 第四级分类（细项）- 如果自定义分类失败，使用通用分类
                if 'custom_category_level4' not in bill:
                    bill['category_level4'] = self._classify_level4(bill)
                    if bill['category_level4'] == '未分类':
                        bill['filter_reason'] = '需要补充四级关键词'
                        self.need_level4_keywords.append(bill)
                        continue
                else:
                    bill['category_level4'] = bill['custom_category_level4']
                
                # 分类成功，标记为已分类
                bill['classification_status'] = '已分类'
                
            except Exception as e:
                print(f"分类异常 - 时间: {bill['datetime']}, 交易对象: {bill['counterparty']}, 错误: {e}")
                bill['filter_reason'] = f'分类异常: {str(e)}'
                self.need_level4_keywords.append(bill)
        
        print(f"通用四级分类完成：")
        print(f"  其他队列: {len(self.other_queue)} 条")
        print(f"  需要补充二级关键词: {len(self.need_level2_keywords)} 条")
        print(f"  需要补充三级关键词: {len(self.need_level3_keywords)} 条")
        print(f"  需要补充四级关键词: {len(self.need_level4_keywords)} 条")
    
    def _classify_level1(self, bill: Dict) -> str:
        """
        第一级分类 - 营业收入和营业总支出
        
        Args:
            bill: 账单数据字典
            
        Returns:
            str: 一级分类结果
        """
        bill_type = bill['type']
        
        # 如果是收入类型，归入营业收入
        if bill_type == 'income':
            return '营业收入'
        
        # 如果是支出类型，归入营业总支出
        elif bill_type == 'expense':
            return '营业总支出'
        
        # 不计收支的情况
        else:
            return '其他'
    
    def _classify_level2(self, bill: Dict) -> str:
        """
        第二级分类
        
        Args:
            bill: 账单数据字典
            
        Returns:
            str: 二级分类结果
        """
        level1 = bill['category_level1']
        description = bill['description'].lower()
        counterparty = bill['counterparty'].lower()
        text_to_check = f"{description} {counterparty}"
        
        if level1 == '营业收入':
            # 主营业务收入（工资）
            if any(keyword in text_to_check for keyword in ['工资', '薪资', '月薪', '奖金', '绩效']):
                return '主营业务收入'
            # 其他业务收入(兼职)
            elif any(keyword in text_to_check for keyword in ['兼职', '副业', '咨询', '服务']):
                return '其他业务收入'
            # 投资收益
            elif any(keyword in text_to_check for keyword in ['余额宝', '基金', '理财', '投资', '股票', '证券', '蚂蚁财富']):
                return '投资收益'
            # 被动收入
            elif any(keyword in text_to_check for keyword in ['租金', '房租', '分红', '股息']):
                return '被动收入'
            # 意外收入
            elif any(keyword in text_to_check for keyword in ['红包', '奖励', '退款', '返还', '淘宝', '签到', '提现']):
                return '意外收入'
            else:
                return '其他营业收入'
        
        elif level1 == '营业总支出':
            # 管理费用
            if any(keyword in text_to_check for keyword in ['房租', '水费', '电费', '燃气', '手机', '话费', '网络', '宽带', '保险', '医疗', '医院', '税费', '培训', '课程', '学习', '书籍', '教育']):
                return '管理费用'
            # 销售费用（个人消费）
            elif any(keyword in text_to_check for keyword in ['外卖', '餐饮', '餐厅', '超市', '购物', '打车', '交通', '地铁', '公交', '加油', '游戏', '电影', '娱乐', '服装', '衣服', '数码', '电子', '旅游', '份子钱', '随礼', '易而购', '百货', '店内购物']):
                return '销售费用'
            # 财务费用（利息/手续费）
            elif any(keyword in text_to_check for keyword in ['利息', '手续费', '财务', '花呗', '还款']):
                return '财务费用'
            # 其他费用
            else:
                return '其他费用'
        
        else:
            return '未分类'
    
    def _classify_level3(self, bill: Dict) -> str:
        """
        第三级分类
        
        Args:
            bill: 账单数据字典
            
        Returns:
            str: 三级分类结果
        """
        level2 = bill['category_level2']
        description = bill['description'].lower()
        counterparty = bill['counterparty'].lower()
        text_to_check = f"{description} {counterparty}"
        
        if level2 == '管理费用':
            # 房租
            if any(keyword in text_to_check for keyword in ['房租', '租金']):
                return '房租'
            # 水电气费
            elif any(keyword in text_to_check for keyword in ['水费', '电费', '燃气费', '水电']):
                return '水电气费'
            # 网络/手机费
            elif any(keyword in text_to_check for keyword in ['手机', '话费', '网络', '宽带', '通讯']):
                return '网络/手机费'
            # 保险/医疗
            elif any(keyword in text_to_check for keyword in ['保险', '医疗', '医院', '药店', '体检']):
                return '保险/医疗'
            # 税费
            elif any(keyword in text_to_check for keyword in ['税费', '税收', '税务']):
                return '税费'
            # 学习提升
            elif any(keyword in text_to_check for keyword in ['培训', '课程', '学习', '书籍', '教育']):
                return '学习提升'
            else:
                return '其他管理费用'
        
        elif level2 == '销售费用':
            # 食品
            if any(keyword in text_to_check for keyword in ['外卖', '餐饮', '餐厅', '超市', '食品', '零食', '水果']):
                return '食品'
            # 交通
            elif any(keyword in text_to_check for keyword in ['打车', '交通', '地铁', '公交', '加油', '滴滴', '高德']):
                return '交通'
            # 娱乐
            elif any(keyword in text_to_check for keyword in ['游戏', '电影', '娱乐', '视频', '音乐']):
                return '娱乐'
            # 购物
            elif any(keyword in text_to_check for keyword in ['购物', '服装', '衣服', '数码', '电子', '商品']):
                return '购物'
            # 旅游
            elif any(keyword in text_to_check for keyword in ['旅游', '旅行', '酒店', '机票']):
                return '旅游'
            # 人情往来
            elif any(keyword in text_to_check for keyword in ['份子钱', '随礼', '人情', '礼金']):
                return '人情往来'
            else:
                return '其他销售费用'
        
        elif level2 == '财务费用':
            if '利息' in text_to_check:
                return '利息'
            elif '手续费' in text_to_check:
                return '手续费'
            else:
                return '其他财务费用'
        
        elif level2 == '其他费用':
            if any(keyword in text_to_check for keyword in ['随礼', '份子钱']):
                return '随礼/份子钱'
            elif '罚款' in text_to_check:
                return '罚款'
            else:
                return '其他费用'
        
        # 处理"其他"类型的分类
        elif level2 == '未分类':
            # 对于不计收支的类型，尝试重新分类
            if bill['type'] == 'neutral':
                if any(keyword in text_to_check for keyword in ['余额宝', '基金', '理财', '投资', '蚂蚁财富', '兴银货币']):
                    return '投资理财'
                elif any(keyword in text_to_check for keyword in ['转账', '充值', '提现', '自动转入', '单次转入']):
                    return '资金流转'
                else:
                    return '其他不计收支'
            else:
                return '未分类'
        
        else:
            return '未分类'
    
    def _classify_level4(self, bill: Dict) -> str:
        """
        第四级分类（细项）
        
        Args:
            bill: 账单数据字典
            
        Returns:
            str: 四级分类结果
        """
        level1 = bill['category_level1']
        level2 = bill['category_level2']
        level3 = bill['category_level3']
        description = bill['description'].lower()
        counterparty = bill['counterparty'].lower()
        text_to_check = f"{description} {counterparty}"
        
        # 营业收入细项
        if level1 == '营业收入':
            if level2 == '主营业务收入':
                if '工资' in text_to_check or '薪资' in text_to_check or '月薪' in text_to_check:
                    return '工资'
                elif '奖金' in text_to_check or '绩效' in text_to_check:
                    return '奖金'
                else:
                    return '其他工资收入'
            
            elif level2 == '其他业务收入':
                if '兼职' in text_to_check or '副业' in text_to_check:
                    return '兼职收入'
                elif '咨询' in text_to_check or '服务' in text_to_check:
                    return '咨询服务'
                else:
                    return '其他业务收入'
            
            elif level2 == '投资收益':
                if '余额宝' in text_to_check or '基金' in text_to_check:
                    return '理财收益'
                elif '股票' in text_to_check or '证券' in text_to_check:
                    return '股票收益'
                else:
                    return '其他投资收益'
            
            elif level2 == '被动收入':
                if '租金' in text_to_check or '房租' in text_to_check:
                    return '租金收入'
                elif '分红' in text_to_check or '股息' in text_to_check:
                    return '分红收入'
                else:
                    return '其他被动收入'
            
            elif level2 == '意外收入':
                if '红包' in text_to_check or '奖励' in text_to_check:
                    return '红包奖励'
                elif '退款' in text_to_check or '返还' in text_to_check:
                    return '退款返还'
                else:
                    return '其他意外收入'
        
        # 营业总支出细项
        elif level1 == '营业总支出':
            if level2 == '管理费用':
                if level3 == '房租':
                    return '房租'
                elif level3 == '水电气费':
                    if '电费' in text_to_check:
                        return '电费'
                    elif '水费' in text_to_check:
                        return '水费'
                    elif '燃气' in text_to_check:
                        return '燃气费'
                    else:
                        return '其他水电费'
                elif level3 == '网络/手机费':
                    if '手机' in text_to_check or '话费' in text_to_check:
                        return '手机费'
                    elif '网络' in text_to_check or '宽带' in text_to_check:
                        return '网络费'
                    else:
                        return '其他通讯费'
                elif level3 == '保险/医疗':
                    if '保险' in text_to_check:
                        return '保险费'
                    elif '医疗' in text_to_check or '医院' in text_to_check:
                        return '医疗费'
                    else:
                        return '其他保险医疗费'
                elif level3 == '税费':
                    return '税费'
                elif level3 == '学习提升':
                    if '培训' in text_to_check or '课程' in text_to_check:
                        return '培训费'
                    elif '书籍' in text_to_check or '学习' in text_to_check:
                        return '学习费用'
                    else:
                        return '其他学习费用'
            
            elif level2 == '销售费用':
                if level3 == '食品':
                    if '外卖' in text_to_check:
                        return '外卖'
                    elif '超市' in text_to_check or '购物' in text_to_check:
                        return '超市购物'
                    elif '餐厅' in text_to_check or '饭店' in text_to_check:
                        return '餐厅用餐'
                    else:
                        return '其他食品'
                elif level3 == '交通':
                    if '打车' in text_to_check or '滴滴' in text_to_check:
                        return '网约车'
                    elif '地铁' in text_to_check or '公交' in text_to_check:
                        return '公共交通'
                    elif '加油' in text_to_check:
                        return '加油费'
                    else:
                        return '其他交通费'
                elif level3 == '娱乐':
                    if '游戏' in text_to_check:
                        return '游戏'
                    elif '电影' in text_to_check or '视频' in text_to_check:
                        return '影视娱乐'
                    else:
                        return '其他娱乐'
                elif level3 == '购物':
                    if '服装' in text_to_check or '衣服' in text_to_check:
                        return '服装'
                    elif '数码' in text_to_check or '电子' in text_to_check:
                        return '数码产品'
                    else:
                        return '其他购物'
                elif level3 == '旅游':
                    return '旅游'
                elif level3 == '人情往来':
                    if '份子钱' in text_to_check or '随礼' in text_to_check:
                        return '份子钱'
                    else:
                        return '其他人情往来'
            
            elif level2 == '财务费用':
                if '利息' in text_to_check:
                    return '利息'
                elif '手续费' in text_to_check:
                    return '手续费'
                else:
                    return '其他财务费用'
            
            elif level2 == '其他费用':
                if '随礼' in text_to_check or '份子钱' in text_to_check:
                    return '随礼'
                elif '罚款' in text_to_check:
                    return '罚款'
                else:
                    return '其他费用'
        
        # 处理"其他"类型的四级分类
        elif level1 == '其他':
            if level2 == '未分类':
                if level3 == '投资理财':
                    if '余额宝' in text_to_check:
                        return '余额宝'
                    elif '基金' in text_to_check or '蚂蚁财富' in text_to_check:
                        return '基金理财'
                    else:
                        return '其他理财'
                elif level3 == '资金流转':
                    if '转账' in text_to_check:
                        return '转账'
                    elif '充值' in text_to_check:
                        return '充值'
                    elif '提现' in text_to_check:
                        return '提现'
                    else:
                        return '其他资金操作'
                else:
                    return '其他不计收支'
            else:
                return '未分类'
        
        return '未分类'
    
    def display_bills_table(self, bills: List[Dict], title: str = "账单数据") -> None:
        """
        显示统一格式的账单表格
        
        Args:
            bills: 账单数据列表
            title: 表格标题
        """
        if not bills:
            print(f"没有找到{title}数据")
            return
        
        print(f"\n{title} (共 {len(bills)} 条记录):")
        print("=" * 150)
        
        # 准备表格数据
        table_data = []
        for bill in bills:
            type_text = '收入' if bill['type'] == 'income' else ('支出' if bill['type'] == 'expense' else '不计收支')
            table_data.append([
                bill['datetime'].strftime('%Y-%m-%d %H:%M'),
                '支付宝' if bill['platform'] == 'alipay' else '微信',
                bill['counterparty'][:15] + '...' if len(bill['counterparty']) > 15 else bill['counterparty'],
                bill['description'][:20] + '...' if len(bill['description']) > 20 else bill['description'],
                type_text,
                f"{bill['amount']:.2f}",
                bill['original_category'][:10] + '...' if len(bill['original_category']) > 10 else bill['original_category'],
                bill['status'],
                bill['payment_method'][:10] + '...' if len(bill['payment_method']) > 10 else bill['payment_method'],
                bill.get('category_level1', '未分类'),
                bill.get('category_level2', '未分类'),
                bill.get('category_level3', '未分类'),
                bill.get('category_level4', '未分类')
            ])
        
        # 使用tabulate显示表格
        headers = ['时间', '平台', '交易对方', '商品描述', '类型', '金额', '原始分类', '交易状态', '支付方式', '一级分类', '二级分类', '三级分类', '四级分类']
        print(tabulate(table_data, headers=headers, tablefmt='grid'))
        
        # 统计信息
        total_income = round(sum(bill['amount'] for bill in bills if bill['type'] == 'income'), 2)
        total_expense = round(sum(bill['amount'] for bill in bills if bill['type'] == 'expense'), 2)
        total_neutral = round(sum(bill['amount'] for bill in bills if bill['type'] == 'neutral'), 2)
        
        print(f"\n统计信息:")
        print(f"总收入: {total_income:.2f} 元")
        print(f"总支出: {total_expense:.2f} 元")
        print(f"不计收支: {total_neutral:.2f} 元")
        print(f"净收入: {total_income - total_expense:.2f} 元")
    
    def export_to_excel(self, filename: str = None) -> None:
        """
        导出数据到Excel文件
        
        Args:
            filename: 输出文件名，如果为None则自动生成
        """
        if not self.valid_bills_data and not self.failed_transactions:
            print("没有数据可导出")
            return
        
        if filename is None:
            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
            filename = f"账单分析结果_{timestamp}.xlsx"
        
        # 准备有效数据
        export_data = []
        for bill in self.valid_bills_data:
            type_text = '收入' if bill['type'] == 'income' else ('支出' if bill['type'] == 'expense' else '不计收支')
            export_data.append({
                '时间': bill['datetime'].strftime('%Y-%m-%d %H:%M:%S'),
                '平台': '支付宝' if bill['platform'] == 'alipay' else '微信',
                '交易对方': bill['counterparty'],
                '商品描述': bill['description'],
                '类型': type_text,
                '金额': bill['amount'],
                '原始分类': bill['original_category'],
                '交易状态': bill['status'],
                '支付方式': bill['payment_method'],
                '一级分类': bill.get('category_level1', ''),
                '二级分类': bill.get('category_level2', ''),
                '三级分类': bill.get('category_level3', ''),
                '四级分类': bill.get('category_level4', ''),
                '分类状态': bill.get('classification_status', '未分类'),
                '过滤原因': bill.get('filter_reason', ''),
                '备注': bill['remark']
            })
        
        # 准备失败交易数据
        failed_data = []
        for bill in self.failed_transactions:
            type_text = '收入' if bill['type'] == 'income' else ('支出' if bill['type'] == 'expense' else '不计收支')
            failed_data.append({
                '时间': bill['datetime'].strftime('%Y-%m-%d %H:%M:%S'),
                '平台': '支付宝' if bill['platform'] == 'alipay' else '微信',
                '交易对方': bill['counterparty'],
                '商品描述': bill['description'],
                '类型': type_text,
                '金额': bill['amount'],
                '原始分类': bill['original_category'],
                '交易状态': bill['status'],
                '支付方式': bill['payment_method'],
                '过滤原因': bill.get('filter_reason', '交易失败'),
                '备注': bill['remark']
            })
        
        # 创建Excel文件，包含多个工作表
        with pd.ExcelWriter(filename, engine='openpyxl') as writer:
            if export_data:
                df_valid = pd.DataFrame(export_data)
                df_valid.to_excel(writer, sheet_name='有效数据', index=False)
            
            if failed_data:
                df_failed = pd.DataFrame(failed_data)
                df_failed.to_excel(writer, sheet_name='失败交易', index=False)
            
            # 添加统计信息
            summary_data = {
                '统计项目': [
                    '原始数据总数',
                    '有效数据总数',
                    '失败交易数',
                    '跨平台互转数',
                    '同平台互转数',
                    '其他类型数',
                    '需要补充二级关键词数',
                    '需要补充三级关键词数',
                    '需要补充四级关键词数'
                ],
                '数量': [
                    len(self.bills_data) + len(self.failed_transactions),
                    len(self.valid_bills_data),
                    len(self.failed_transactions),
                    len(self.cross_platform_transfers),
                    len(self.same_platform_transfers),
                    len(self.other_queue),
                    len(self.need_level2_keywords),
                    len(self.need_level3_keywords),
                    len(self.need_level4_keywords)
                ]
            }
            df_summary = pd.DataFrame(summary_data)
            df_summary.to_excel(writer, sheet_name='统计汇总', index=False)
        
        print(f"数据已导出到: {filename}")
        print(f"包含工作表: 有效数据、失败交易、统计汇总")
    
    
    def show_main_menu(self) -> None:
        """
        显示主菜单
        """
        while True:
            print("\n" + "=" * 60)
            print("账单分析系统 - 增强版本")
            print("=" * 60)
            print("1. 显示默认数据（微信和支付宝各10条）")
            print("2. 显示支付宝全部数据")
            print("3. 显示微信全部数据")
            print("4. 显示每月汇总统计")
            print("5. 导出数据到Excel")
            print("6. 高级功能")
            print("7. 查看异常队列")
            print("0. 退出程序")
            print("=" * 60)
            
            choice = input("请选择操作 (0-7): ").strip()
            
            if choice == '0':
                print("感谢使用，再见！")
                break
            elif choice == '1':
                self.display_default_data()
            elif choice == '2':
                self.display_alipay_data()
            elif choice == '3':
                self.display_wechat_data()
            elif choice == '4':
                self.show_monthly_summary_menu()
            elif choice == '5':
                self.export_to_excel()
            elif choice == '6':
                self.show_advanced_menu()
            elif choice == '7':
                self.show_exception_queues_menu()
            else:
                print("无效选择，请重新输入！")
    
    def show_monthly_summary_menu(self) -> None:
        """
        显示每月汇总统计菜单
        """
        while True:
            print("\n" + "=" * 60)
            print("每月汇总统计")
            print("=" * 60)
            print("1. 平台默认分类标准")
            print("2. 自定义二级分类")
            print("3. 自定义三级分类")
            print("0. 返回主菜单")
            print("=" * 60)
            
            choice = input("请选择统计类型 (0-3): ").strip()
            
            if choice == '0':
                break
            elif choice == '1':
                self.display_platform_default_summary()
            elif choice == '2':
                self.display_custom_level2_summary()
            elif choice == '3':
                self.display_custom_level3_summary()
            else:
                print("无效选择，请重新输入！")
    
    def show_advanced_menu(self) -> None:
        """
        显示高级功能菜单
        """
        while True:
            print("\n" + "=" * 60)
            print("高级功能")
            print("=" * 60)
            print("1. 用户1统计")
            print("2. 用户2（无用户2，请重新选择）")
            print("3. 用户3（无用户3，请重新选择）")
            print("0. 返回主菜单")
            print("=" * 60)
            
            choice = input("请选择用户 (0-3): ").strip()
            
            if choice == '0':
                break
            elif choice == '1':
                self.display_user1_statistics()
            elif choice == '2':
                print("无用户2，请重新选择")
            elif choice == '3':
                print("无用户3，请重新选择")
            else:
                print("无效选择，请重新输入！")
    
    def show_exception_queues_menu(self) -> None:
        """
        显示异常队列查看菜单
        """
        while True:
            print("\n" + "=" * 60)
            print("查看异常队列")
            print("=" * 60)
            print("1. 交易失败队列")
            print("2. 疑似跨平台互转队列")
            print("3. 疑似同平台互转队列")
            print("4. 其他队列")
            print("5. 需要补充二级关键词队列")
            print("6. 需要补充三级关键词队列")
            print("7. 需要补充四级关键词队列")
            print("0. 返回主菜单")
            print("=" * 60)
            
            choice = input("请选择队列 (0-7): ").strip()
            
            if choice == '0':
                break
            elif choice == '1':
                self.display_exception_queue("交易失败队列", self.failed_transactions)
            elif choice == '2':
                self.display_transfer_queue("疑似跨平台互转队列", self.cross_platform_transfers)
            elif choice == '3':
                self.display_transfer_queue("疑似同平台互转队列", self.same_platform_transfers)
            elif choice == '4':
                self.display_exception_queue("其他队列", self.other_queue)
            elif choice == '5':
                self.display_exception_queue("需要补充二级关键词队列", self.need_level2_keywords)
            elif choice == '6':
                self.display_exception_queue("需要补充三级关键词队列", self.need_level3_keywords)
            elif choice == '7':
                self.display_exception_queue("需要补充四级关键词队列", self.need_level4_keywords)
            else:
                print("无效选择，请重新输入！")
    
    def display_platform_default_summary(self) -> None:
        """
        显示平台默认分类标准统计
        """
        print("\n" + "=" * 80)
        print("平台默认分类标准统计")
        print("=" * 80)
        
        # 统计原始分类
        original_categories = {}
        for bill in self.valid_bills_data:
            if 'classification_status' in bill and bill['classification_status'] == '已分类':
                category = bill.get('original_category', '未分类')
                if category not in original_categories:
                    original_categories[category] = {'count': 0, 'amount': 0}
                original_categories[category]['count'] += 1
                original_categories[category]['amount'] += bill['amount']
        
        if original_categories:
            print(f"{'分类名':<20} {'数量':<10} {'金额':<15}")
            print("-" * 50)
            for category, stats in sorted(original_categories.items()):
                print(f"{category:<20} {stats['count']:<10} {stats['amount']:<15.2f}")
        else:
            print("没有找到已分类的数据")
    
    def display_custom_level2_summary(self) -> None:
        """
        显示自定义二级分类统计
        """
        print("\n" + "=" * 80)
        print("自定义二级分类统计")
        print("=" * 80)
        
        # 统计二级分类
        level2_categories = {}
        for bill in self.valid_bills_data:
            if 'classification_status' in bill and bill['classification_status'] == '已分类':
                category = bill.get('category_level2', '未分类')
                if category not in level2_categories:
                    level2_categories[category] = {'count': 0, 'amount': 0}
                level2_categories[category]['count'] += 1
                level2_categories[category]['amount'] += bill['amount']
        
        if level2_categories:
            print(f"{'二级分类名':<20} {'数量':<10} {'金额':<15}")
            print("-" * 50)
            for category, stats in sorted(level2_categories.items()):
                print(f"{category:<20} {stats['count']:<10} {stats['amount']:<15.2f}")
        else:
            print("没有找到已分类的数据")
    
    def display_custom_level3_summary(self) -> None:
        """
        显示自定义三级分类统计
        """
        print("\n" + "=" * 80)
        print("自定义三级分类统计")
        print("=" * 80)
        
        # 统计三级分类
        level3_categories = {}
        for bill in self.valid_bills_data:
            if 'classification_status' in bill and bill['classification_status'] == '已分类':
                category = bill.get('category_level3', '未分类')
                if category not in level3_categories:
                    level3_categories[category] = {'count': 0, 'amount': 0}
                level3_categories[category]['count'] += 1
                level3_categories[category]['amount'] += bill['amount']
        
        if level3_categories:
            print(f"{'三级分类名':<20} {'数量':<10} {'金额':<15}")
            print("-" * 50)
            for category, stats in sorted(level3_categories.items()):
                print(f"{category:<20} {stats['count']:<10} {stats['amount']:<15.2f}")
        else:
            print("没有找到已分类的数据")
    
    def display_user1_statistics(self) -> None:
        """
        显示用户1统计信息
        """
        print("\n" + "=" * 80)
        print("用户1统计信息")
        print("=" * 80)
        
        # 按平台分组统计
        platform_stats = {}
        for bill in self.valid_bills_data:
            if 'classification_status' in bill and bill['classification_status'] == '已分类':
                platform = bill['platform']
                if platform not in platform_stats:
                    platform_stats[platform] = {
                        'income': 0, 'expense': 0, 'neutral': 0, 'count': 0
                    }
                
                if bill['type'] == 'income':
                    platform_stats[platform]['income'] += bill['amount']
                elif bill['type'] == 'expense':
                    platform_stats[platform]['expense'] += bill['amount']
                else:
                    platform_stats[platform]['neutral'] += bill['amount']
                
                platform_stats[platform]['count'] += 1
        
        # 显示各平台统计
        for platform, stats in platform_stats.items():
            platform_name = '支付宝' if platform == 'alipay' else '微信'
            print(f"\n{platform_name}平台:")
            print(f"  收入: {stats['income']:.2f} 元")
            print(f"  支出: {stats['expense']:.2f} 元")
            print(f"  不计收支: {stats['neutral']:.2f} 元")
            print(f"  净收支: {stats['income'] - stats['expense']:.2f} 元")
            print(f"  交易笔数: {stats['count']} 笔")
        
        # 年度汇总
        total_income = sum(stats['income'] for stats in platform_stats.values())
        total_expense = sum(stats['expense'] for stats in platform_stats.values())
        total_neutral = sum(stats['neutral'] for stats in platform_stats.values())
        total_count = sum(stats['count'] for stats in platform_stats.values())
        
        print(f"\n年度汇总:")
        print(f"  总收入: {total_income:.2f} 元")
        print(f"  总支出: {total_expense:.2f} 元")
        print(f"  不计收支: {total_neutral:.2f} 元")
        print(f"  净收支: {total_income - total_expense:.2f} 元")
        print(f"  总交易笔数: {total_count} 笔")
    
    def display_exception_queue(self, queue_name: str, queue_data: List) -> None:
        """
        显示异常队列数据
        
        Args:
            queue_name: 队列名称
            queue_data: 队列数据
        """
        if not queue_data:
            print(f"\n{queue_name}为空")
            return
        
        print(f"\n{queue_name} (共 {len(queue_data)} 条记录):")
        print("=" * 120)
        
        # 准备表格数据
        table_data = []
        for bill in queue_data:
            type_text = '收入' if bill['type'] == 'income' else ('支出' if bill['type'] == 'expense' else '不计收支')
            table_data.append([
                bill['datetime'].strftime('%Y-%m-%d %H:%M'),
                '支付宝' if bill['platform'] == 'alipay' else '微信',
                bill['counterparty'][:20] + '...' if len(bill['counterparty']) > 20 else bill['counterparty'],
                bill['description'][:25] + '...' if len(bill['description']) > 25 else bill['description'],
                type_text,
                f"{bill['amount']:.2f}",
                bill.get('filter_reason', '未知原因')[:20] + '...' if len(bill.get('filter_reason', '')) > 20 else bill.get('filter_reason', '未知原因')
            ])
        
        headers = ['时间', '平台', '交易对象', '商品描述', '类型', '金额', '过滤原因']
        print(tabulate(table_data, headers=headers, tablefmt='grid'))
    
    def display_transfer_queue(self, queue_name: str, queue_data: List) -> None:
        """
        显示互转队列数据
        
        Args:
            queue_name: 队列名称
            queue_data: 队列数据
        """
        if not queue_data:
            print(f"\n{queue_name}为空")
            return
        
        print(f"\n{queue_name} (共 {len(queue_data)} 对记录):")
        print("=" * 150)
        
        # 准备表格数据
        table_data = []
        for transfer in queue_data:
            bill1 = transfer['bill1']
            bill2 = transfer['bill2']
            time_diff = transfer['time_diff']
            
            table_data.append([
                bill1['datetime'].strftime('%Y-%m-%d %H:%M'),
                '支付宝' if bill1['platform'] == 'alipay' else '微信',
                bill1['counterparty'][:15] + '...' if len(bill1['counterparty']) > 15 else bill1['counterparty'],
                f"{bill1['amount']:.2f}",
                "→",
                bill2['datetime'].strftime('%Y-%m-%d %H:%M'),
                '支付宝' if bill2['platform'] == 'alipay' else '微信',
                bill2['counterparty'][:15] + '...' if len(bill2['counterparty']) > 15 else bill2['counterparty'],
                f"{bill2['amount']:.2f}",
                f"{time_diff:.0f}秒"
            ])
        
        headers = ['时间1', '平台1', '对象1', '金额1', '→', '时间2', '平台2', '对象2', '金额2', '间隔']
        print(tabulate(table_data, headers=headers, tablefmt='grid'))

    def display_default_data(self) -> None:
        """
        显示默认数据（微信和支付宝各10条）
        """
        alipay_bills = [bill for bill in self.valid_bills_data if bill['platform'] == 'alipay'][:10]
        wechat_bills = [bill for bill in self.valid_bills_data if bill['platform'] == 'wechat'][:10]
        
        self.display_bills_table(alipay_bills, "支付宝数据（最近10条）")
        self.display_bills_table(wechat_bills, "微信数据（最近10条）")
    
    def display_alipay_data(self) -> None:
        """
        显示支付宝全部数据
        """
        alipay_bills = [bill for bill in self.valid_bills_data if bill['platform'] == 'alipay']
        self.display_bills_table(alipay_bills, "支付宝全部数据")
    
    def display_wechat_data(self) -> None:
        """
        显示微信全部数据
        """
        wechat_bills = [bill for bill in self.valid_bills_data if bill['platform'] == 'wechat']
        self.display_bills_table(wechat_bills, "微信全部数据")
    

    def run(self) -> None:
        """
        运行分析程序主流程
        """
        print("开始账单分析...")
        
        # 加载账单
        self.load_bills()
        
        if not self.bills_data:
            print("没有找到有效的账单数据")
            return
        
        print(f"成功加载 {len(self.bills_data)} 条账单记录")
        
        # 数据预处理
        self.preprocess_bills()
        
        # 分类账单
        self.classify_bills()
        
        # 显示菜单
        self.show_main_menu()


def main():
    """
    主函数
    """
    analyzer = BillAnalyzerFinal()
    analyzer.run()


if __name__ == "__main__":
    main()
